#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"
#include <string>
#include <cstdlib>
#include <vector>
#include <ctime>
#include <iostream>
#include <cmath>
using namespace std;

//Constantes

const int LAR = 300;
const int ALT = 500;
const int BPP = 32;
const int TDA = 30;

//Superficies

SDL_Surface *screen;
SDL_Surface *bg;
SDL_Surface *player;
SDL_Surface *enemy;
SDL_Surface *shot[3];
SDL_Surface *blow;
SDL_Surface *lost;
SDL_Surface *pausescreen;
SDL_Surface *startgame;
SDL_Surface *highscores;
SDL_Surface *exitgame;
SDL_Surface *text;
SDL_Surface *texthealth;
SDL_Surface *text2;
SDL_Surface *textpoints;

//Variaveis

int bgloop; //Auxilia o movimento do plano de fundo
int mx; //Guarda a coordenda X do movimento do player
int my; //Guarda a coordenda Y do movimento do player
int tiro[100]; //Cada bloco do vetor sera uma variavel para um tiro
int posxtiro[100]; //Posicoes X dos tiros
int posytiro[100]; //Posicoes Y dos tiros
int numtiro; //Numero do tiro
int subidatiro[100];//Coeficiente de subida do tiro
int enemyX[100];//Cada bloco do vetor sera uma variavel para um inimigo
int posyenemy;//Posicao Y dos inimigos
int posxenemy[100];//Posicoes X dos inimigos
int numenemy; //Numero do inimigo
int enemyhealth[100]; //Vida do inimigo
int descidaenemy[100];
int andaenemy[100];
int retornaenemy[100];
int tiroinimigo[100];
int posxti[100]; //Posicao horizontal do tiro
int posyti[100]; //Posicao vertical do tiro
int descidati[100]; //Coeficiente de descida do tiro
int health; // Health do player
unsigned int points; // Pontos do player
char textoHealth[4]; // Texto que vai receber a variavel health
char textoPoints[10];
int contti; // Contagem dos tiros dos inimigos


TTF_Font *font = NULL;
SDL_Color textColor = {255, 255, 255};

//Prototipos das funcoes

SDL_Surface* load_image(std::string filename);
void apply_image(int x, int y, SDL_Surface* source, SDL_Surface* destination);
bool init();
bool close();

//Eventos
SDL_Event evento;
Uint8 *keystates = SDL_GetKeyState(NULL); //Guarda estado de teclas

//Main
int main(){
        bool quit = false;
	int state = 1; //Estado do jogo
	bool gameover = false; //Derrota
	bool start = false;

        bgloop = 0; //Variavel p/ auxliar o loop do plano de fundo
        mx = 140; //Posicao horizontal do player
        my = 450; //Posicao vertical do player
        numtiro = 0;
        numenemy = 0;
	health = 10;
	points = 0;
        srand(time(NULL)); //Inicializacao de semente randomica
	contti = 0;

        init();
	
	// Carregamento das superficies
        bg = load_image("img/BG.png");
        player = load_image("img/ship.png");
        shot[0] = load_image("img/lasergreen.png");
        shot[1] = load_image("img/laserblue.png");
        shot[2] = load_image("img/spark.png");
        enemy = load_image("img/enemy1.png");
        blow = load_image("img/blow1.png");
	lost = load_image("img/gameover.png");
	pausescreen = load_image("img/pause.png");
	startgame = load_image("img/start.png");
	highscores = load_image("img/high.png");
	exitgame = load_image("img/exit.png");
	font = TTF_OpenFont("img/Solov2.ttf", 14);
	text = TTF_RenderText_Solid(font, "Health: ", textColor);
	text2 = TTF_RenderText_Solid(font, "Points: ", textColor);

	apply_image(0, 0, bg, screen);
	apply_image(23, 150, startgame, screen);
	apply_image(23, 220, highscores, screen);
	apply_image(23, 290, exitgame, screen);
	SDL_Flip(screen);
	SDL_Delay(1000);

	for(int i=0; i<=100; i++){
        tiro[i]=0;
        subidatiro[i]=0;
        enemyX[i]=0;
        descidaenemy[i]=0;
        posxenemy[i]=(rand()%300); //Posicao inicial horizontal dos inimigos e aleatoria
        andaenemy[i]=1;
        retornaenemy[i]=1;
        enemyhealth[i]=4;
	tiroinimigo[i]=0;
        }

	while (quit==false){
		while (SDL_PollEvent(&evento)){
			if (evento.type==SDL_QUIT){
				quit = true;
			}
			if( evento.type == SDL_MOUSEBUTTONDOWN ){
			        if( evento.button.button == SDL_BUTTON_LEFT ){
					int x, y;
		
					x = evento.button.x;
					y = evento.button.y;
	
					if((x>23)&&(x<278)&&(y>150)&&(y<215))
						goto loop;
					if((x>23)&&(x<278)&&(y>220)&&(y<285))
						goto finish2;
					if((x>23)&&(x<278)&&(y>290)&&(y<355))
						goto finish2;
				}
			}
		}
	}
/**************************************************Loop do jogo******************************************************/
	goto loop;
	pause:
	apply_image(100, 220, pausescreen, screen);
	SDL_Flip(screen);
	while (SDL_PollEvent(&evento)){
		if (keystates[SDLK_RETURN])
			state*=-1;
	}
	loop:	
        while (quit==false){
	
	// Conversão de variavel em string
	sprintf(textoHealth, "%d", health);
	texthealth = TTF_RenderText_Solid(font, textoHealth, textColor);
	sprintf(textoPoints, "%d", points);
	textpoints = TTF_RenderText_Solid(font, textoPoints, textColor);

                while (SDL_PollEvent(&evento)){ // So entra no while quando acontece algum evento
                        // Deteccao eventual do estado da tecla espaco, e do comando "sair"(usuario aperta X)
                        if (evento.type==SDL_QUIT)
                                quit = true;
                        if (keystates[SDLK_SPACE]==true){ //Se a tecla espaco for pressionada...
                                tiro[numtiro%100]=1; //O tiro de numero "numtiro" sera disparado
                                posxtiro[numtiro%100] = mx+8; //A posicao horizontal do tiro sera definida
                                posytiro[numtiro%100] = my;  //A posicao vertical INICIAL do tiro sera definida
                                numtiro++; //O numero "numtiro" sera incrementado para a proxima ocorrencia
                        }
			if (keystates[SDLK_RETURN])
				state*=-1;
                }
                        // Deteccao continua do estado das teclas de movimento
                        if (keystates[SDLK_UP])
                                my-=5;
                        if (keystates[SDLK_DOWN])
                                my+=5;
                        if (keystates[SDLK_LEFT])
                                mx-=5;
                        if (keystates[SDLK_RIGHT])
                                mx+=5;

		// Plotagem das imagens
                apply_image(0, bgloop-500, bg, screen);
                apply_image(0, bgloop, bg, screen);
                apply_image(mx, my, player, screen);
		apply_image(5, 485, text, screen);
		apply_image(75, 485, texthealth, screen);
		apply_image(170, 485, text2, screen);
		apply_image(240, 485, textpoints, screen);

		if (state==-1) // Ponto de gerenciamento do estado do jogo
			goto pause;

/************************************************Inimigos**********************************************************************/

                if (bgloop%40==0){
                        enemyX[numenemy%100]=1;
                        numenemy++;
                }
		if (((bgloop%100+400)%(rand()%3)==0)&&(tiroinimigo[contti%100]==0)){ // Inicializacao dos tiros do inimigo
			tiroinimigo[contti%100]=1;
			contti++;
		}
                for (int i=0; i<=100; i++){
                        if (enemyX[i]==1){
                                apply_image(posxenemy[i]+andaenemy[i]*retornaenemy[i], posyenemy+descidaenemy[i], enemy, screen);
                                if (bgloop%5==0){
                                        descidaenemy[i]+=2;
                                }
                                andaenemy[i]+=rand()%4+1;
                                if (posxenemy[i]+andaenemy[i]*retornaenemy[i]>280){
                                        posxenemy[i] = 270;
                                        andaenemy[i] = 0;
                                        retornaenemy[i] = -retornaenemy[i];
                                }
                                if (posxenemy[i]+andaenemy[i]*retornaenemy[i]<0){
                                        posxenemy[i] = 0;
                                        andaenemy[i] = 0;
                                        retornaenemy[i] = -retornaenemy[i];
                                }
				for (int j=0; j<100; j++){
					if (tiroinimigo[j]==0){// Tiro Inimigo
						posxti[j]=posxenemy[i]+andaenemy[i]*retornaenemy[i]+10;
						posyti[j]=posyenemy+descidaenemy[i];
					}
					if (tiroinimigo[j]==1){
						apply_image(posxti[j], posyti[j]+10*descidati[j], shot[2], screen);
						descidati[j]++;
					}
					if (posyti[j]>=501){
						posyti[j]=-1;
						tiroinimigo[j]=0;
						descidati[j]=0;
					}
				}
                        }
                }

/*******************************************Aparecimento dos tiros e colisoes**********************************************************/

                for (int i=0; i<=100; i++){ //Faz 100 copias do codigo abaixo, uma para cada bloco do vetor tiro
                        if (tiro[i]==1){ //Se o tiro for disparado...
                                apply_image(posxtiro[i], posytiro[i]-14*subidatiro[i], shot[0], screen); //Plotar imagem e subtrair 10 vezes o coeficiente de subida do tiro
                                subidatiro[i]++; //Incrementar coeficiente de subida
                        }
                        if (posytiro[i]-14*subidatiro[i]<0) {
                                tiro[i]=0;
                                subidatiro[i] = 0;
                        }
                        for (int n=0; n<=100; n++){ //Colisoes tiro-inimigo
                                int x1 = posxenemy[n]+andaenemy[n]*retornaenemy[n]+5;
                                int x2 = posxtiro[i]-5;
                                int y1 = posyenemy+descidaenemy[n]+10;
                                int y2 = posytiro[i]-15*subidatiro[i];
                                if ((sqrt(pow(x1-x2, 2)+pow(y1-y2, 2))<=12)&&(((enemyX[n]==1)&&(tiro[i]==1)))){  //Triangulacao para achar a distancia entre o tiro e o inimigo
                                        apply_image(x2, y2, blow, screen);
                                        tiro[i]=0;
                                        posxtiro[i]=-10;
                                        subidatiro[i]=0;
                                        enemyhealth[n]--;
                                }
                                if (enemyhealth[n]==0){
                                        enemyX[n]=0;
					descidaenemy[n]=0;
					posyenemy=0;
					points+=10;
					enemyhealth[n]=4;
                                }
                        }
			for (int n=0; n<=100; n++){ //Colisoes tiro-player
					int x1 = mx+10;
					int x2 = posxti[n];
					int y1 = my+10;
					int y2 = posyti[n]+10*descidati[n];
					if ((sqrt(pow(x1-x2, 2)+pow(y1-y2, 2))<=15)&&(tiroinimigo[n]==1)){ //Triangulacao de colisao tiro-player
						apply_image(x2-5, y2, blow, screen);
						tiroinimigo[n]=0;
						posxti[n]=-300;
						health--;
						descidati[n] = 500;
					}
					int a1 = mx+10;
					int a2 = posxenemy[n]+andaenemy[n]*retornaenemy[n];
					int b1 = my+10;
					int b2 = posyenemy+descidaenemy[n];
					if ((sqrt(pow(a1-a2, 2)+pow(b1-b2, 2))<=15)&&(enemyX[n]==1)){ //Triangulacao de colisao inimigo-player
						apply_image(x2-5, y2, blow, screen);
						enemyX[n]=0;
						posxenemy[n]=-20;
						health--;
						descidaenemy[n] = 0;
					}
					if (health==0)
						gameover=true;
			}
                }
/*******************************************************************************************************************************/
		
                SDL_Flip(screen);
                SDL_Delay(TDA);
                bgloop+=3;
                
                // Efetivo loop do plano de fundo e limitações de movimento do player
                if (bgloop>=500)
                        bgloop = 0;
                if (my>460)
                        my = 460;
                if (mx<0)
                        mx = 0;
                if (my<0)
                        my = 0;
                if (mx>280)
                        mx = 280;
		if (gameover==true)
			goto finish;
        }
        close();
        return 0;
	finish:
	while(quit==false){
		apply_image(50, 150, lost, screen);		
		while (SDL_PollEvent(&evento))		
			if (evento.type==SDL_QUIT)
				quit = true;
		SDL_Delay(60);
		SDL_Flip(screen);
	}
	finish2:
	close();
	return 0;
}
/******************************************Fim do loop do jogo**************************************************************/
//Corpos das funcoes

SDL_Surface* load_image(string filename){
        SDL_Surface* protImage;
        SDL_Surface* optImage;
        protImage = IMG_Load(filename.c_str());
        if (protImage!=NULL)
                optImage = SDL_DisplayFormatAlpha(protImage);
                SDL_FreeSurface(protImage);
        return optImage;
}
void apply_image(int x, int y, SDL_Surface* source, SDL_Surface* destination){
        SDL_Rect offset;
        offset.x = x;
        offset.y = y;
        SDL_BlitSurface(source, NULL, destination, &offset);
}
bool init(){
        if (SDL_Init(SDL_INIT_EVERYTHING)==-1)
                return false;
	if (TTF_Init()==-1)
		return false;
        screen = SDL_SetVideoMode(LAR, ALT, BPP, SDL_SWSURFACE);
        SDL_WM_SetCaption("Game", NULL);
	return true;
}
bool close(){
        SDL_FreeSurface(screen);
	TTF_CloseFont(font);
        SDL_Quit();
}
